

local getmetatable = getmetatable
local setmetatable = setmetatable
local module = module
local require = require
local table = table
local pairs = pairs
local tostring = tostring

local print = print
local type = type

module('fit.Summary')
_VERSION='0.2'

local Fixture = require('fit.Fixture')
local Parse = require('fit.Parse')

--[[
Ordered table iterator, allow to iterate on the natural order of the keys of a
table.

From: http://lua-users.org/wiki/SortedIteration
]]

function __genOrderedIndex( t )
    local orderedIndex = {}
    for key in pairs(t) do
        table.insert( orderedIndex, key )
    end
    table.sort( orderedIndex )
    return orderedIndex
end

--[[
From: http://lua-users.org/wiki/SortedIteration
]]
function orderedNext(self, t, state)
    -- Equivalent of the next function, but returns the keys in the alphabetic
    -- order. We use a temporary ordered key table that is stored in the
    -- table being iterated.
    if state == nil then
        -- the first time, generate the index
        t.__orderedIndex = __genOrderedIndex( t )
        key = t.__orderedIndex[1]
        return key, t[key]
    end
    -- fetch the next value
    key = nil
    for i = 1,table.getn(t.__orderedIndex) do
        if t.__orderedIndex[i] == state then
            key = t.__orderedIndex[i+1]
        end
    end

    if key then
        return key, t[key]
    end

    -- no more value to return, cleanup
    t.__orderedIndex = nil
    return
end

local function doTable(self, table)
    self.summary[self.countsKey] = self.counts:string()
    table.parts.more = self:rows(self.summary, nil)
end

local function rows(self, t, state)
    local key,val = self:orderedNext(t, state)
    if key ~= nil then
        local result = self:tr(self:td(key, self:td(t[key], nil)), self:rows(t, key))
        if (key == self.countsKey) then
            self:mark(result)
        end
        return result
    else
        return nil
    end
end

local function tr(self, parts, more)
    return Parse("tr", nil, parts, more)
end

local function td(self, body, more)
    return Parse("td", self:info(nil, body), nil, more)
end

local function mark(self, row)
    -- mark summary good/bad without counting beyond here
    cell = row.parts.more
    if (self.counts.wrong + self.counts.exceptions > 0) then
        self:wrong(cell)
        self.counts.wrong = self.counts.wrong - 1 -- don't count
    else
        self:right(cell)
        self.counts.right = self.counts.right - 1 -- don't count
    end
end

-- Constructor
function __call()
    local summary = Fixture()

    summary.countsKey = "counts"
    summary.doTable = doTable
    summary.tr = tr
    summary.td = td
    summary.mark = mark
    summary.rows = rows

    summary.orderedNext = orderedNext

    return summary
end

setmetatable(_M, _M)
